package server

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"kratos-layout/internal/conf"
	"kratos-layout/middleware/logging"
	"kratos-layout/pkg/logger"
	"log"
	httpOri "net/http"
	"net/url"
	"os"
	"path"

	"github.com/go-kratos/kratos/v2/middleware/recovery"
	"github.com/go-kratos/kratos/v2/transport/http"
	"github.com/gorilla/websocket"
)

func HttpServerOptions(c *conf.Server) []http.ServerOption {
	opts := []http.ServerOption{
		http.Middleware(
			logging.Server(),
			recovery.Recovery(),
		),
	}
	return opts
}

// RegisterOtherHTTPServer register other http server
func RegisterOtherHTTPServer(srv *http.Server) {
	//r := srv.Route("/")
	//r.GET("/api/download", DownloadHandler())
	//r.POST("/api/upload", UploadHandler())

	// Websocket
	//router := mux.NewRouter()
	//router.HandleFunc("/ws/example", WsExampleHandler)
	//srv.HandlePrefix("/", router)
}

var upgrader = websocket.Upgrader{}

func WsExampleHandler(w httpOri.ResponseWriter, r *httpOri.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.Errorf("upgrade: %v", err)
		return
	}
	defer c.Close()
	for {
		mt, message, err := c.ReadMessage()
		if err != nil {
			logger.Errorf("read message: %v", err)
			break
		}
		log.Printf("recv: %s", message)
		err = c.WriteMessage(mt, message)
		if err != nil {
			logger.Errorf("write message: %v", err)
			break
		}
	}
}

// DownloadHandler 下载处理器
// 修改内容：
// 1. 将tmp_file改为正确的文件名，包含路径
// 2. 将/api/download改为正确的URL
func DownloadHandler() func(httpCtx http.Context) error {
	return func(httpCtx http.Context) error {
		// 在此处可以从httpCtx解析参数，如：
		// var in interface{}
		// if err := httpCtx.BindQuery(&in); err != nil {
		//      return err
		// }

		// 加入middleware链，可以走认证等中间件流程
		http.SetOperation(httpCtx, "/api/download")
		h := httpCtx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
			err := Download(httpCtx, "tmp_file")
			return nil, err
		})
		_, err := h(httpCtx, nil)
		return err
	}
}

// UploadHandler 上传处理器
// 修改内容：
// 1. 将appHandler赋值为正确的业务处理函数
// 2. 将/api/upload改为正确的URL
func UploadHandler() func(httpCtx http.Context) error {
	var appHandler func(ctx context.Context, content []byte) (interface{}, error)
	return func(httpCtx http.Context) error {
		http.SetOperation(httpCtx, "/api/upload")
		h := httpCtx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
			err := Upload(httpCtx, appHandler)
			return nil, err
		})
		_, err := h(httpCtx, nil)
		return err
	}
}

// Download 下载文件
func Download(ctx http.Context, fileName string) error {
	currentDir, _ := os.Getwd()
	fName := path.Join(currentDir, path.Base(fileName))
	file, err := os.Open(fName)
	if err != nil {
		logger.Errorf("Download: Open %s error %v", fName, err)
		return errors.New("internal server error")
	}
	defer file.Close()
	fi, _ := file.Stat()

	ctx.Header().Set("Content-Type", "application/octet-stream")
	ctx.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size()))
	ctx.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename*=utf-8''%s", url.QueryEscape(path.Base(fName))))

	data, err := ioutil.ReadAll(file)
	if err != nil {
		logger.Errorf("Download: ReadAll %s error %v", fName, err)
		return errors.New("internal server error")
	}
	_, err = ctx.Response().Write(data)
	if err != nil {
		logger.Errorf("Download: Write %s error %v", fName, err)
		return errors.New("internal server error")

	}
	return nil
}

// Upload 上传文件
func Upload(ctx http.Context, appHandler func(ctx context.Context, content []byte) (interface{}, error)) error {
	// Parse our multipart form, 10 << 20 specifies a maximum
	// upload of 10 MB files.
	_ = ctx.Request().ParseMultipartForm(10 << 20)
	// FormFile returns the first file for the given key `myFile`
	// it also returns the FileHeader so we can get the Filename,
	// the Header and the size of the file
	file, handler, err := ctx.Request().FormFile("file")
	if err != nil {
		logger.Errorf("Upload: retrieving the file error: %v", err)
		return errors.New("request parameter error")
	}
	defer file.Close()

	logger.Infof("Upload: uploaded file: %+v", handler.Filename)
	logger.Infof("Upload: file size: %+v", handler.Size)
	logger.Infof("Upload: MIME header: %+v", handler.Header)

	// read all of the contents of our uploaded file into a
	// byte array
	fileBytes, err := ioutil.ReadAll(file)
	if err != nil {
		logger.Errorf("Upload: ReadAll file error: %v", err)
		return errors.New("read file content error")
	}

	result, _ := appHandler(ctx, fileBytes)
	return ctx.JSON(200, result)
}
